package cc.eddic.pratice.programmingparadigms.nginxlog.impl;


import cc.eddic.pratice.programmingparadigms.nginxlog.LogItem;
import cc.eddic.pratice.programmingparadigms.nginxlog.LogReport;
import cc.eddic.pratice.programmingparadigms.nginxlog.NginxLogItem;
import cc.eddic.pratice.programmingparadigms.nginxlog.PageViewsAndUniqueVisitors;
import lombok.EqualsAndHashCode;

import java.util.*;
import java.util.stream.Collectors;

public class LogReportLhImpl implements LogReport {

    @Override
    public PageViewsAndUniqueVisitors pageViewsAndUniqueVisitors(List<NginxLogItem> items) {
        long pv = items.size();
        if (pv == 0) return new PageViewsAndUniqueVisitors(0, 0);
        long uv = items.stream().map(item -> new pvAndUv(item.getIp(), item.getUserAgent())).distinct().count();
        return new PageViewsAndUniqueVisitors(pv, uv);
    }

    @Override
    public Map<Integer, PageViewsAndUniqueVisitors> pageViewsAndUniqueVisitorsByHour(List<NginxLogItem> items) {
        Map<Integer, PageViewsAndUniqueVisitors> pvanduvbyhour = new HashMap<>();
        List<NginxLogItem> oneHour = new ArrayList<>();
        int timestart = 0;
        int timestop = 0;
        for (int i = 0; i < items.size(); i++) {
            if (i != items.size() - 1) {
                timestart = Integer.parseInt(items.get(i).getTime().substring(12, 14));
                timestop = Integer.parseInt(items.get(i + 1).getTime().substring(12, 14));
                if (timestart == timestop) oneHour.add(items.get(i));
            }
            if (timestart != timestop || i == items.size() - 1) {
                oneHour.add(items.get(i));
                timestart = Integer.parseInt(items.get(i).getTime().substring(12, 14));
                pvanduvbyhour.put(timestart, pageViewsAndUniqueVisitors(oneHour));
                oneHour.clear();
            }
        }
        return pvanduvbyhour;
    }

    @Override
    public List<PathModel> pageViewsAndUniqueVisitorsByPath(List<LogItem> items) {
        return items.stream().collect(Collectors.groupingBy(LogItem::getPath))
                .entrySet().stream()
                .map(S -> new PathModel(S.getKey(),
                        pageViewsAndUniqueVisitorsLogItem(S.getValue()).getPageViews(),
                        pageViewsAndUniqueVisitorsLogItem(S.getValue()).getUniqueVisitors())
                ).sorted(Comparator.comparing(PathModel::getPv).reversed())
                .collect(Collectors.toList());
    }

    public PageViewsAndUniqueVisitors pageViewsAndUniqueVisitorsLogItem(List<LogItem> items) {
        long pv = items.size();
        List<pvAndUv> pvAndUvList = new ArrayList<>();
        for (LogItem item : items) {
            pvAndUvList.add(new pvAndUv(item.getIp(), item.getUserAgent()));
        }
        return new PageViewsAndUniqueVisitors(pv, (int) pvAndUvList.stream().distinct().count());
    }

    @EqualsAndHashCode
    private static class pvAndUv {
        String ip;
        String userAgent;

        public pvAndUv(String ip, String userAgent) {
            this.ip = ip;
            this.userAgent = userAgent;
        }

    }
}
